/*
 * Copyright (c) 2009, Jan Pastor. All Rights Reserved.
 */

package sk.jp.jitag.ui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sk.jp.commons.ui.ExceptionDialog;
import sk.jp.commons.ui.InfoDialog;
import sk.jp.commons.ui.LeaveGridLayout;
import sk.jp.commons.ui.WarningDialog;
import sk.jp.commons.utils.LogMsg;
import sk.jp.jitag.dao.JitagDao;
import sk.jp.jitag.dao.db4o.CollectionsFactory;
import sk.jp.jitag.model.config.FileFormat;
import sk.jp.jitag.model.config.MediaType;
import sk.jp.jitag.model.config.MediaTypeClass;
import sk.jp.jitag.ui.common.IconLoader;
import sk.jp.jitag.ui.common.Icons;
import sk.jp.jitag.util.Defaults;
import sk.jp.jitag.util.Msg;

/**
 * Select media for profile dialog.
 */
public class SelectMediaDialog extends JDialog implements ActionListener {

    private static final Logger log = LoggerFactory.getLogger(SelectMediaDialog.class);

    private enum ActionCode {
        save,
        cancel,
        addFileFormat,
        removeFileFormat,
        addFileExtension,
        removeFileExtension,
        ;
    }

    private Map<MediaTypeClass.Items, MediaType> model;

    private Map<MediaTypeClass.Items, JList> fileFormats = null;
    private Map<MediaTypeClass.Items, JList> fileExtensions = null;
    private JButton btnOk = null;
    private MediaTypeClass.Items selectedTabType = MediaTypeClass.Items.values()[0];

    //----------------------------------------------------------------------

    /**
     * Initialize dialog.
     * @param ownerDialog
     * @param mediaTypes list of configured media types.
     * @param jitagDao instance of DAO.
     */
    public SelectMediaDialog(JDialog ownerDialog, List<MediaType> mediaTypes,
                             JitagDao jitagDao) {
        super(ownerDialog, Msg.mediaDialogTitle.value(), true);

        jitagDao.beginTransaction();
        model = new LinkedHashMap<MediaTypeClass.Items, MediaType>(5);
        model.put(MediaTypeClass.Items.image,
                  new MediaType(jitagDao.get(MediaTypeClass.Items.image.name(), MediaTypeClass.class)));
        model.put(MediaTypeClass.Items.text,
                  new MediaType(jitagDao.get(MediaTypeClass.Items.text.name(), MediaTypeClass.class)));
        model.put(MediaTypeClass.Items.video,
                  new MediaType(jitagDao.get(MediaTypeClass.Items.video.name(), MediaTypeClass.class)));
        model.put(MediaTypeClass.Items.audio,
                  new MediaType(jitagDao.get(MediaTypeClass.Items.audio.name(), MediaTypeClass.class)));
        model.put(MediaTypeClass.Items.other,
                  new MediaType(jitagDao.get(MediaTypeClass.Items.other.name(), MediaTypeClass.class)));
        for (MediaType mediaType : mediaTypes) {
            model.put(mediaType.getTypeClass().getTypeClassCode(), mediaType);
        }
        fileFormats = new LinkedHashMap<MediaTypeClass.Items, JList>();
        fileExtensions = new LinkedHashMap<MediaTypeClass.Items, JList>();
    }

    //----------------------------------------------------------------------

    /**
     * Opens dialog with current configuration profile values.
     */
    public void open(){
        init(model);

        pack();
        btnOk.requestFocusInWindow();

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension screenDimension = toolkit.getScreenSize();
        Dimension size = getSize();
        setLocation((screenDimension.width - size.width) / 2,
                    (screenDimension.height - size.height) / 2);

        setVisible(true);
    }

    /**
     * Returns modified media types configuration or null if user cancell the dialog.
     * @return modified media types configuration or null if user cancell the dialog.
     */
    public List<MediaType> getMediaTypes() {
        List<MediaType> resultModel;
        if (model != null){
            resultModel = CollectionsFactory.createList(model.values());
        }else{
            resultModel = null;
        }
        log.trace(LogMsg.out("resultModel", resultModel));
        return resultModel;
    }

    //----------------------------------------------------------------------

    @Override
    public void setVisible(boolean visible) {
        if(!visible){
            //on close
            actionCancel();
        }
        super.setVisible(visible);
    }

    private void init(final Map<MediaTypeClass.Items, MediaType> model){
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
        JScrollPane mainPannelScrollable = new JScrollPane(tabbedPane);
        contentPane.add(mainPannelScrollable, BorderLayout.CENTER);
        tabbedPane.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                int selectedIndex = ((JTabbedPane) e.getSource()).getSelectedIndex();
                selectedTabType = (new ArrayList<MediaTypeClass.Items>(model.keySet()))
                                    .get(selectedIndex);
                log.trace(LogMsg.toString("Selected tab", "tabMediaType", selectedTabType));
            }
        });

        // Tabs
        for (MediaType mediaType : model.values()) {
            JPanel mtPanel = createMediaTypeTab(mediaType.getTypeClass().getTypeClassCode(),
                                                mediaType.getFileFormats());
            tabbedPane.addTab(
                Defaults.mediaTypeLabel.get(mediaType.getTypeClass().getTypeClassCode()),
                IconLoader.loadIcon(Defaults.mediaTypeIcon.get(mediaType.getTypeClass().getTypeClassCode())),
                mtPanel);
        }

        //Buttons
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        contentPane.add(buttonPanel, BorderLayout.PAGE_END);

        //
        btnOk = createButton(Msg.commonOk, ActionCode.save); //OK
        buttonPanel.add(btnOk);
//        buttonPanel.add(createButton(Msg.commonCancel, ActionCode.cancel));  //Cancel

        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    }

    private JPanel createMediaTypeTab(final MediaTypeClass.Items mediaType,
                                      List<FileFormat> fileFormats){
        LeaveGridLayout leaveGridLayout;
        leaveGridLayout = new LeaveGridLayout(5, 2, 4, 5,
                                                LeaveGridLayout.HAlign.left,
                                                LeaveGridLayout.VAlign.top);
        JPanel mainPanel = new JPanel(leaveGridLayout);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(6, 4, 6, 4));

        // //
        mainPanel.add(new JLabel(Msg.mediaDialogFileFormat.value()));//File format
        mainPanel.add(new JLabel(" "));
        mainPanel.add(new JLabel(" "));
        mainPanel.add(new JLabel(Msg.mediaDialogFileExt.value()));//File extension
        mainPanel.add(new JLabel(" "));

        // //
        DefaultListModel listModel = new DefaultListModel();
        for (FileFormat fileFormat : fileFormats) {
            listModel.addElement(fileFormat.getLabel());
        }
        final JList fileFormatList = new JList(listModel);
        this.fileFormats.put(mediaType, fileFormatList);
        fileFormatList.setVisibleRowCount(8);
        fileFormatList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        fileFormatList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if(!e.getValueIsAdjusting()){
                    String ff = (String) fileFormatList.getSelectedValue();
                    actionFileFormatSelected(mediaType, ff);
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(fileFormatList,
                                                  JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                                  JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(164, 128));
        mainPanel.add(scrollPane);

        LeaveGridLayout lgl = new LeaveGridLayout(1, 2);
        JPanel panel = new JPanel(lgl);
        mainPanel.add(panel);
        panel.add(createImgButton(Icons.add, ActionCode.addFileFormat));
        panel.add(createImgButton(Icons.remove, ActionCode.removeFileFormat));
        mainPanel.add(new JLabel(" "));

        //
        JList fileExtList = new JList(new DefaultListModel());
        fileExtensions.put(mediaType, fileExtList);
        fileExtList.setVisibleRowCount(8);
        fileExtList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        scrollPane = new JScrollPane(fileExtList,
                                     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                                     JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setPreferredSize(new Dimension(164, 128));
        mainPanel.add(scrollPane);
        lgl = new LeaveGridLayout(1, 2);
        panel = new JPanel(lgl);
        mainPanel.add(panel);
        panel.add(createImgButton(Icons.add, ActionCode.addFileExtension));
        panel.add(createImgButton(Icons.remove, ActionCode.removeFileExtension));

        return mainPanel;
    }

    private JButton createButton(Msg btnLabel, ActionCode actionCode){
        JButton button = new JButton(btnLabel.value());
        button.setActionCommand(actionCode.name());
        button.addActionListener(this);
        return button;
    }

    private JButton createImgButton(Icons icon, ActionCode actionCode){
        ImageIcon imageIcon = IconLoader.loadIcon(icon);
        JButton button = new JButton(imageIcon);
        button.setPreferredSize(new Dimension(imageIcon.getIconWidth()+4,
                                              imageIcon.getIconHeight()+4));
        button.setActionCommand(actionCode.name());
        button.addActionListener(this);
        return button;
    }

    public void actionPerformed(ActionEvent event) {
        try {
            processAction(ActionCode.valueOf(event.getActionCommand()));
        }catch(Exception e){
            ExceptionDialog.show(this, e);
        }
    }

    @SuppressWarnings({"IfStatementWithTooManyBranches"})
    private void processAction(ActionCode actionCode){
        log.trace(LogMsg.inp("actionCode", actionCode));
        if(actionCode == ActionCode.cancel){
            actionCancel();
        }else if(actionCode == ActionCode.save){
            actionSave();
        }else if(actionCode == ActionCode.addFileFormat){
            actionAddFileFormat();
        }else if(actionCode == ActionCode.removeFileFormat){
            actionRemoveFileFormat();
        }else if(actionCode == ActionCode.addFileExtension){
            actionAddFileExtension();
        }else if(actionCode == ActionCode.removeFileExtension){
            actionRemoveFileExtension();
        }else{
            new InfoDialog().show(this, "Not yet implemented");
        }
    }

    private void actionCancel(){
        model = null;
        dispose();
    }

    private void actionSave(){
        dispose();
    }

    private void actionAddFileFormat(){
        FileFormatDialog fileFormatDialog = new FileFormatDialog(this);
        fileFormatDialog.open();
        FileFormat fileFormat = fileFormatDialog.getFileFormat();
        if(fileFormat != null && selectedTabType != null){
            DefaultListModel listModel = (DefaultListModel) fileFormats
                                            .get(selectedTabType).getModel();
            if(!listModel.contains(fileFormat.getLabel())){
                listModel.addElement(fileFormat.getLabel());
                model.get(selectedTabType).addFileFormat(fileFormat);
            }
        }
    }

    private void actionRemoveFileFormat(){
        JList list = fileFormats.get(selectedTabType);
        DefaultListModel listModel = (DefaultListModel) list.getModel();
        String selectedFormatLabel = (String) list.getSelectedValue();

        if(selectedFormatLabel != null){
            model.get(selectedTabType).removeFileFormat(selectedFormatLabel);     
            listModel.removeElement(selectedFormatLabel);
        }
    }

    private void actionAddFileExtension(){
        if(fileFormats.get(selectedTabType).getSelectedValue() == null){
            new WarningDialog().show(this, Msg.mediaDialogNoFileFormSel.value()); //No file format is selected
            return;
        }

        FileExtensionDialog fileExtensionDialog = new FileExtensionDialog(this);
        fileExtensionDialog.open();
        String ext = fileExtensionDialog.getFileExtension();
        if(ext != null){
            DefaultListModel listModel;
            listModel = (DefaultListModel) fileExtensions.get(selectedTabType).getModel();
            if(!listModel.contains(ext)){
                listModel.addElement(ext);

                //Get selected file format
                Object selFormatLabel = fileFormats.get(selectedTabType).getSelectedValue();

                //Update model - add extension to format
                List<FileFormat> fileFormatList = model.get(selectedTabType).getFileFormats();
                for (FileFormat fileFormat : fileFormatList) {
                    if(fileFormat.getLabel().equals(selFormatLabel)){
                        fileFormat.addExtension(ext);
                    }
                }
            }
        }
    }

    private void actionRemoveFileExtension(){
        String selExtLabel = (String) fileExtensions.get(selectedTabType).getSelectedValue();
        String selFormatLabel = (String) fileFormats.get(selectedTabType).getSelectedValue();

        DefaultListModel extList;
        extList = (DefaultListModel) fileExtensions.get(selectedTabType).getModel();
        extList.removeElement(selExtLabel);

        List<FileFormat> formats = model.get(selectedTabType).getFileFormats();
        for (FileFormat format : formats) {
            if(format.getLabel().equals(selFormatLabel)){
                log.trace(LogMsg.toString("Removing file extension from model",
                                          "mediaType", selectedTabType,
                                          "fileFormat", selFormatLabel,
                                          "fileExtension", selExtLabel));
                format.removeExtension(selExtLabel);
            }
        }
    }

    private void actionFileFormatSelected(MediaTypeClass.Items mediaTypeItem,
                                          String selectedFormatLabel){
        log.trace("mediaType: "+mediaTypeItem+", Selected: "+selectedFormatLabel);

        DefaultListModel listModel;
        listModel = (DefaultListModel) fileExtensions.get(mediaTypeItem).getModel();
        listModel.clear();
        if(selectedFormatLabel != null){
            List<FileFormat> formats = model.get(mediaTypeItem).getFileFormats();
            for (FileFormat format : formats) {
                if(format.getLabel().equals(selectedFormatLabel)){
                    List<String> extensions = format.getExtensions();
                    for (String extension : extensions) {
                        listModel.addElement(extension);
                    }
                    break;
                }
            }
        }
    }

}